import {
  ref,
  reactive,
  watch,
  onBeforeUnmount,
  type WatchStopHandle,
} from 'vue';
import { useRoute, useRouter, onBeforeRouteLeave } from 'vue-router';
import type { FormInstance } from 'element-plus';
import { isBtoa } from '@/utils/util';

const isDev = import.meta.env.MODE === 'development';

/**
 * 分页列表组合函数
 *
 * @export
 * @template T
 * @template U
 * @param {(param: T) => Promise<HttpResponse<U>>} requestFunc 请求函数
 * @param {(boolean | { replace: boolean })} [isRoute=false] 是否使用路由进行查询
 * @param {(data: U) => void} [callback] 响应回调函数
 * @param {boolean} [queryBase64=true] 参数是否base64编码
 * @return {*}
 */
export default function useList<T, U extends pageResult>(
  requestFunc: (param: T) => Promise<HttpResponse<U>>,
  isRoute: boolean | { replace: boolean } = false,
  callback?: (data: U) => void,
  queryBase64 = true
) {
  const router = useRouter();
  const route = useRoute();
  // 搜索loading
  const searchLoading = ref<boolean>(false);
  // 搜索表单
  const searchForm = ref<Omit<T, 'size' | 'page'>>();
  // 排序字段
  const sortParams = reactive<{ sort_field: string; sort_rule: 1 | 2 }>({
    sort_field: '', // 排序字段
    sort_rule: 1, // 1-升序，2-降序
  });

  let listParams: any = null;
  // 列表loading
  const listLoading = ref<boolean>(false);
  // 返回的原始数据
  const data = ref<U>();
  // 返回的列表数据（适配新结构 records）
  const list = ref<any[]>([]);
  // 当前页码，默认第一页
  const currentPage = ref<number>(1);
  // 每页条数，默认10条
  const pageSize = ref<number>(10);
  // 总条数
  const total = ref<number>(0);
  // 搜索表单引用
  const searchRef = ref<FormInstance>();

  /**
   * 合并参数
   */
  function mergeParams() {
    if (sortParams.sort_field) {
      listParams = {
        ...searchForm.value,
        ...sortParams,
      };
    } else {
      listParams = {
        ...searchForm.value,
      };
    }
  }

  /**
   * 获取列表
   */
  async function getList(page?: number) {
    if (typeof page === 'number' && page > 0) {
      currentPage.value = page;
    }
    // 合并参数
    mergeParams();

    listLoading.value = true;
    try {
      const res = await requestFunc({
        ...listParams,
        page: currentPage.value,
        size: pageSize.value,
      });
      console.log('---res', res);

      data.value = res.data;
      if (typeof callback === 'function') {
        callback(data.value);
      } else {
        // 适配新结构：data = { records, total, size, current, pages }
        const d: any = data.value;
        const records = Array.isArray(d?.records)
          ? d.records
          : Array.isArray(d?.list)
          ? d.list
          : Array.isArray(d)
          ? d
          : [];
        list.value = records;
        total.value = Number(d?.total ?? d?.count ?? 0);
        // 同步服务端返回的分页信息（若提供）
        currentPage.value = Number(d?.current ?? currentPage.value);
        pageSize.value = Number(d?.size ?? pageSize.value);
      }
    } catch (error) {
      console.log('获取列表数据错误', error);
    } finally {
      listLoading.value = false;
    }
  }

  /**
   * 排序
   * @param {object} {prop, order}
   * @returns
   */
  function handleSort({
    prop,
    order,
  }: {
    prop: string;
    order: 'ascending' | 'descending';
  }) {
    sortParams.sort_field = prop;
    if (order === 'ascending') {
      sortParams.sort_rule = 1;
    } else {
      sortParams.sort_rule = 2;
    }

    if (isRoute) {
      changeRoute(1);
    } else {
      getList(1);
    }
  }

  // #region 普通列表查询操作

  /**
   * 搜索列表
   * @returns
   */
  async function handleSearch() {
    if (searchLoading.value) {
      return;
    }

    if (isDev) {
      // 只有开发环境才会提示
      console.warn(
        'useList:搜索表单searchForm需要提供ref="searchRef"并在组件中返回searchRef和设置相应rules才可以进行表单校验'
      );
    }
    if (searchRef.value) {
      const flag = await searchRef.value.validate().then(
        () => true,
        () => false
      );
      if (!flag) {
        return;
      }
    }

    searchLoading.value = true;
    try {
      await getList(1);
    } finally {
      searchLoading.value = false;
    }
  }

  /**
   * 重置搜索表单
   * @param {boolean} [reSearch=true] 重新搜索，默认true
   * @returns
   */
  function resetSearch(reSearch = true) {
    if (isDev) {
      // 只有开发环境才会提示
      console.warn(
        '搜索表单searchForm需要提供ref="searchRef"并在组件中返回searchRef才可以对表单重置，记得提供prop'
      );
    }
    searchRef.value?.resetFields();

    if (reSearch) {
      handleSearch();
    }
  }

  // #endregion

  // #region 通过路由查询列表操作
  /**
   * 编码参数
   *
   * @param {object} queryParam
   */
  function queryStringify(queryParam: object | undefined) {
    if (!queryParam) {
      return '';
    }
    if (queryBase64) {
      return btoa(encodeURIComponent(JSON.stringify(queryParam)));
    } else {
      return JSON.stringify(queryParam);
    }
  }
  /**
   * 解析参数
   *
   * @param {string} queryParam
   * @return {any}
   */
  function queryParse(queryParam: string) {
    if (queryBase64) {
      const str = isBtoa(queryParam)
        ? decodeURIComponent(atob(queryParam))
        : queryParam;
      if (/^{.*}$/.test(str)) {
        return JSON.parse(str);
      } else {
        return null;
      }
    } else {
      if (/^{.*}$/.test(queryParam)) {
        return JSON.parse(queryParam);
      } else {
        return null;
      }
    }
  }

  // 接口路由监听
  let unwatch: WatchStopHandle | null = null;
  /**
   * 初始化route查询
   *
   * @param {number} [initPage=1] 初始化页码，如果传了initPage但是值是无效的数字且不是大于0的就会重置为1
   * @param {number} [initSize=10] 初始化每页条数 如果传了initSize但是值是无效的数字且不是大于0的就会重置为10
   * @return {*}
   */
  function initRouteQuery(initPage = 1, initSize = 10) {
    if (!isRoute) {
      if (isDev) {
        console.warn(
          '请在useList中传入isRoute参数且为真值后，才会执行该方法后续操作'
        );
      }
      return;
    }

    if (isDev) {
      if (isNaN(initPage) || Number(initPage) < 1) {
        console.warn(
          'initRouteQuery方法的initPage参数为无效值，请传入大于0的正整数，否则会被重置为1继续执行后续操作'
        );
      }
      if (isNaN(initSize) || Number(initSize) < 1) {
        console.warn(
          'initRouteQuery方法的initSize参数为无效值，请传入大于0的正整数，否则会被重置为10继续执行后续操作'
        );
      }
    }

    unwatch = watch(
      route,
      (newVal) => {
        const {
          page,
          pageSize: size,
          searchForm: searchFormQuery,
          sortParams: sortParamsQuery,
        } = newVal.query;
        currentPage.value = Number(
          page || (Number(initPage) > 0 ? initPage : 1)
        );
        pageSize.value = Number(size || (Number(initSize) > 0 ? initSize : 10));

        const searchFormObj = queryParse(searchFormQuery as string);
        if (searchFormObj) {
          searchForm.value = {
            ...searchForm.value,
            ...searchFormObj,
          };
        }

        const sortParamsObj = queryParse(sortParamsQuery as string);
        if (sortParamsObj) {
          const { sort_field, sort_rule } = sortParamsObj;
          sortParams.sort_field = sort_field ?? '';
          sortParams.sort_rule = Number(sort_rule || 1) as 1 | 2;
        }
        getList();
      },
      {
        immediate: true,
      }
    );
  }

  /**
   * 更改route的参数
   *
   * @param {number} [page] 页码
   */
  function changeRoute(page?: number) {
    if (!page) {
      page = currentPage.value;
    }
    router.push({
      ...route,
      query: {
        ...route.query,
        searchForm: queryStringify(searchForm.value),
        sortParams: queryStringify(sortParams),
        page,
        pageSize: pageSize.value,
        timestamp: Date.now(),
      },
      replace: isRoute instanceof Object ? isRoute.replace : false,
    });
  }

  /**
   * 重置路由器参数
   *
   * @param {*} searchFormInit 搜索表单的初始值
   */
  function resetRoute(searchFormInit) {
    searchForm.value = searchFormInit;
    changeRoute(1);
  }

  // 修复路由离开当前页面时继续当前查询的bug
  onBeforeRouteLeave(() => {
    unwatch && unwatch();
  });

  // 确保当前页面销毁后移出监听
  onBeforeUnmount(() => {
    unwatch && unwatch();
  });

  // #endregion

  return {
    searchRef,
    searchLoading,
    searchForm,
    sortParams,
    listParams,
    currentPage,
    pageSize,
    total,
    data,
    list,
    listLoading,
    getList,
    handleSort,
    // 以下为普通查询方法
    handleSearch,
    resetSearch,
    // 以前为路由查询方法
    initRouteQuery,
    changeRoute,
    resetRoute,
  };
}
